/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.vce.web.election;

import com.vce.Audit;
import com.vce.BusinessException;
import com.vce.election.domain.*;
import com.vce.web.ManagedBean;
import java.util.*;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import static org.apache.commons.lang.StringUtils.isBlank;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;

/**
 *
 * @author Ggutierrez
 */
public class DocumentBean extends ManagedBean {

    private ElectionType electionType; // Presidente, Alcaldes, Concejales
    private Counting counting;  // Rapido, paralelo, oficial
    private Round round; // Primera, Segunda
    private Document document;
    private Town town;
    private BallotCentre ballotCentre;
    private Jrv jrv;
    private Set<Vote> votes;
    private List<Town> towns;
    private List<BallotCentre> ballots;
    private List<Jrv> jrvs;
    private Float voteFsln;
    private Float votePlc;
    private Float voteAln;
    private Float voteMrs;
    private Float votePrn;
    private Float voteYatama;
    private Float votePc;
    private Float votePli;
    private List<Fiscal> fiscals;
    private String fiscalName;
    private List<Member> members;
    private String memberName;
    private Integer fiscalCount;
    private Integer memberCount;

    public DocumentBean() {
    }

    @Override
    public String startup() {
        init();
        return "success";
    }

    public String init() {
        String election = getParameterMap().get("election");
        counting = Counting.valueOf(getParameterMap().get("counting"));
        round = Round.valueOf(getParameterMap().get("round"));

        if (!isBlank(election)) {
            electionType = getElection().getElectionType(election);
        } else {
            electionType = getElection().getCurrentElectionType(true);
        }
        reset();

        return "success";
    }

    public String create() {
        reset();

        return "success";
    }

    public String save() {
        System.out.println("Init save");
        if (validations().equals("fail")) {
            return "fail";
        }

        if (jrv == null) {
            addErrorMessage("Debe informar la JRV");
            return "fail";
        }
        if (jrv != null && jrv.getCode() == null) {
            addErrorMessage("Debe informar codigo de la JRV");
            return "fail";
        }

        // Add votes for every Party
        // Plc
        Vote vPlc = new Vote();
        vPlc.setDocument(document);
        vPlc.setParty(getElection().getParty(1, electionType));
        vPlc.setAmount(votePlc);
        votes.add(vPlc);

        // Fsln
        Vote vFsln = new Vote();
        vFsln.setDocument(document);
        vFsln.setParty(getElection().getParty(2, electionType));
        vFsln.setAmount(voteFsln);
        votes.add(vFsln);

        // Pc
        Vote vPc = new Vote();
        vPc.setDocument(document);
        vPc.setParty(getElection().getParty(4, electionType));
        vPc.setAmount(votePc);
        votes.add(vPc);

        // Yatama
        Vote vYatama = new Vote();
        vYatama.setDocument(document);
        vYatama.setParty(getElection().getParty(8, electionType));
        vYatama.setAmount(voteYatama);
        votes.add(vYatama);

        // Aln
        Vote vAln = new Vote();
        vAln.setDocument(document);
        vAln.setParty(getElection().getParty(9, electionType));
        vAln.setAmount(voteAln);
        votes.add(vAln);

        // Prn
        Vote vPrn = new Vote();
        vPrn.setDocument(document);
        vPrn.setParty(getElection().getParty(10, electionType));
        vPrn.setAmount(votePrn);
        votes.add(vPrn);

        // Pli
        Vote vPli = new Vote();
        vPli.setDocument(document);
        vPli.setParty(getElection().getParty(13, electionType));
        vPli.setAmount(votePli);
        votes.add(vPli);

        document.setElectionType(electionType);
        document.setCounting(counting);
        document.setRound(round);
        document.setJrv(jrv);
        document.setVotes(votes);

        if (fiscals != null && !fiscals.isEmpty()) {
            document.setFiscals(fiscals);
        }

        if (members != null && !members.isEmpty()) {
            document.setMembers(members);
        }

        // Audit
        Audit audit = new Audit();
        audit.setCreatedBy(getElection().getCurrentUser());
        audit.setCreatedDate(new Date());
        audit.setModifiedBy(getElection().getCurrentUser());
        audit.setModifiedDate(new Date());

        document.setAudit(audit);
        calculations();

        try {
            getElection().storeDocument(document);
        } catch (HibernateOptimisticLockingFailureException e) {
            clear(document);
            return "fail";
        } catch (BusinessException e) {
            clear(document);
            addErrorMessage("Request was rejected, " + e.getMessage());
            return "fail";
        }

        addErrorMessage("Registro guardado");
        System.out.println("Finished save process");
        reset();
        return "success";
    }

    public void clear(Document document) {
        document.getVotes().clear();
        document.setId(null);
    }

    @Override
    public void reset() {
        document = new Document();
        votes = new HashSet<Vote>();
        jrv = null;
        towns = getElection().findTowns(true);
        fiscals = new ArrayList<Fiscal>();
        members = new ArrayList<Member>();
        fiscalName = null;
        memberName = null;
        ballots = null;
        town = null;
        ballotCentre = null;
        fiscalName = null;

        voteFsln = 0f;
        votePlc = 0f;
        voteAln = 0f;
        voteMrs = 0f;
        votePrn = 0f;
        voteYatama = 0f;
        votePc = 0f;
        votePli = 0f;
        document.setDepositedVotes(0f);
        document.setValidVotes(0f);
        document.setNullVotes(0f);
        document.setCalcDepositedVotes(0f);
        document.setCalcValidVotes(0f);
    }

    public void addFiscal(ActionEvent e) {
        if (!isBlank(fiscalName)) {
            fiscals.add(new Fiscal(fiscalName.toUpperCase(), null));
        } else {
            addErrorMessage("Ingrese el nombre del fiscal");
        }
        fiscalName = null;
    }

    public void deleteFiscal(ActionEvent e) {
        String idval = getParameterMap().get("index");
        int indx = Integer.valueOf(idval);
        Fiscal fiscal = fiscals.get(indx);
        fiscals.remove(fiscal);
    }

    public void addMember(ActionEvent e) {
        if (!isBlank(memberName)) {
            members.add(new Member(memberName.toUpperCase()));
        } else {
            addErrorMessage("Ingrese el nombre del fiscal");
        }
        memberName = null;
    }

    public void deleteMember(ActionEvent e) {
        String idval = getParameterMap().get("index");
        int indx = Integer.valueOf(idval);
        Member member = members.get(indx);
        members.remove(member);
    }

    public void processTownChange(ValueChangeEvent event) throws AbortProcessingException {
        Town oldValue = (Town) event.getOldValue();
        Town newValue = (Town) event.getNewValue();
        String oldString = oldValue != null ? oldValue.getName() : "None";
        String newString = newValue != null ? newValue.getName() : "None";
        System.out.println("Town old value: " + oldString);

        if (newValue != null && (oldValue == null || (oldValue != null && !oldValue.equals(newValue)))) {
            ballots = getElection().findBallotCentres(newValue);
            FacesContext.getCurrentInstance().renderResponse();
        }
    }

    public void processBallotChange(ValueChangeEvent event) throws AbortProcessingException {
        BallotCentre oldValue = (BallotCentre) event.getOldValue();
        BallotCentre newValue = (BallotCentre) event.getNewValue();
        String oldString = oldValue != null ? oldValue.getDescription() : "None";
        String newString = newValue != null ? newValue.getDescription() : "None";
        System.out.println("Ballot new value: " + newString);

        if (newValue != null && (oldValue == null || (oldValue != null && !oldValue.equals(newValue)))) {
            ballotCentre = getElection().getBallotCentre(((BallotCentre) event.getNewValue()).getId());
            FacesContext.getCurrentInstance().renderResponse();
        }
    }

    public ElectionType getElectionType() {
        return electionType;
    }

    public void setElectionType(ElectionType electionType) {
        this.electionType = electionType;
    }

    public Document getDocument() {
        return document;
    }

    public void setDocument(Document document) {
        this.document = document;
    }

    public Counting getCounting() {
        return counting;
    }

    public void setCounting(Counting counting) {
        this.counting = counting;
    }

    public Round getRound() {
        return round;
    }

    public void setRound(Round round) {
        this.round = round;
    }

    public Town getTown() {
        return town;
    }

    public void setTown(Town town) {
        this.town = town;
    }

    public BallotCentre getBallotCentre() {
        return ballotCentre;
    }

    public void setBallotCentre(BallotCentre ballotCentre) {
        this.ballotCentre = ballotCentre;
    }

    public Jrv getJrv() {
        return jrv;
    }

    public void setJrv(Jrv jrv) {
        this.jrv = jrv;
    }

    public Float getVoteFsln() {
        return voteFsln;
    }

    public void setVoteFsln(Float voteFsln) {
        this.voteFsln = voteFsln;
    }

    public Float getVotePlc() {
        return votePlc;
    }

    public void setVotePlc(Float votePlc) {
        this.votePlc = votePlc;
    }

    public Float getVoteAln() {
        return voteAln;
    }

    public void setVoteAln(Float voteAln) {
        this.voteAln = voteAln;
    }

    public Float getVoteMrs() {
        return voteMrs;
    }

    public void setVoteMrs(Float voteMrs) {
        this.voteMrs = voteMrs;
    }

    public Float getVotePrn() {
        return votePrn;
    }

    public void setVotePrn(Float votePrn) {
        this.votePrn = votePrn;
    }

    public Float getVoteYatama() {
        return voteYatama;
    }

    public void setVoteYatama(Float voteYatama) {
        this.voteYatama = voteYatama;
    }

    public Float getVotePc() {
        return votePc;
    }

    public void setVotePc(Float votePc) {
        this.votePc = votePc;
    }

    public Float getVotePli() {
        return votePli;
    }

    public void setVotePli(Float votePli) {
        this.votePli = votePli;
    }

    public Set<Vote> getVotes() {
        return votes;
    }

    public void setVotes(Set<Vote> votes) {
        this.votes = votes;
    }

    public void setTowns(List<Town> towns) {
        this.towns = towns;
    }

    public List<Town> getTowns() {
        return towns;
    }

    public List<BallotCentre> getBallots() {
        return ballots;
    }

    public void setBallots(List<BallotCentre> ballots) {
        this.ballots = ballots;
    }

    public List<Jrv> getJrvs() {
        return jrvs;
    }

    public void setJrvs(List<Jrv> jrvs) {
        this.jrvs = jrvs;
    }    

    public Integer getTotalInserted() {
        return (Integer) getElection().getTotalInsertedDocuments(getElection().getCurrentUser(), counting, electionType);
    }

    public Document getLastInsertedDocument() {
        return getElection().getlastInsertedDocument(getElection().getCurrentUser(), counting, electionType);
    }

    public void calculations() {
        Float nullVotes = document.getNullVotes();
        Float totalVotes = voteFsln + votePlc + votePc + voteYatama + voteAln + votePrn + votePli;

        document.setCalcDepositedVotes(totalVotes + nullVotes);
        document.setCalcValidVotes(totalVotes);
    }

    public String validations() {
        Long limitVotes = 400L;
        Float nullVotes = document.getNullVotes();
        Float validVotes = document.getValidVotes();
        Float depositedvotes = document.getDepositedVotes();

        if (jrv == null) {
            addErrorMessage("Debe informar la JRV");
            return "fail";
        }

        if (voteFsln == null) {
            voteFsln = 0f;
        }
        if (votePlc == null) {
            votePlc = 0f;
        }
        if (votePc == null) {
            votePc = 0f;
        }
        if (voteYatama == null) {
            voteYatama = 0f;
        }
        if (voteAln == null) {
            voteAln = 0f;
        }
        if (voteMrs == null) {
            voteMrs = 0f;
        }
        if (votePrn == null) {
            votePrn = 0f;
        }
        if (votePli == null) {
            votePli = 0f;
        }

        if (nullVotes == null) {
            nullVotes = 0f;
        }

        if (validVotes == null) {
            validVotes = 0f;
        }

        if (depositedvotes == null) {
            depositedvotes = 0f;
        }

        Float calcDepositedVotes = voteFsln + votePlc + votePc + voteYatama + voteAln + votePrn + votePli + nullVotes;
        // Validar que no sea cero la suma
        if (calcDepositedVotes == 0L) {
            addErrorMessage("Suma de votos depositados igual a cero");
            return "fail";
        }

        if (depositedvotes == 0L) {
            addErrorMessage("Suma de votos depositados igual a cero");
            return "fail";
        }

        if (validVotes == 0L) {
            addErrorMessage("Suma de votos igual a cero");
            return "fail";
        }

        if (validVotes + nullVotes != depositedvotes) {
            addErrorMessage("Suma de votos invalida: Votos nulos + Votos Validos = Votos Depositados");
            return "fail";
        }

        // Validar que suma no sea mayor al rango de votos por JRV
        if (calcDepositedVotes > limitVotes) {
            addErrorMessage("Suma de votos mayor a la cantidad de votos por JRV. Marcado para revision.");
            document.setRevision(true);
            return "true";
        } else {
            document.setRevision(false);
        }

        // Validar que las cantidades no sean menor que cero
        if (depositedvotes < 0L) {
            addErrorMessage("Suma de votos depositados no puede ser menor que cero");
            return "fail";
        }

        if (validVotes < 0L) {
            addErrorMessage("Suma de votos validos no puede ser menor que cero");
            return "fail";
        }

        if (nullVotes < 0L) {
            addErrorMessage("Votos nulos no puede ser menor que cero");
            return "fail";
        }

        if (calcDepositedVotes < 0) {
            addErrorMessage("Suma de votos depositados calculados menor que cero");
            return "fail";
        }

        // Validar que el detalle de votos no sea mayor al rango de votos por JRV
        if (voteFsln > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para FSLN");
            return "fail";
        }
        if (votePlc > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para PLC");
            return "fail";
        }
        if (votePc > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para PC");
            return "fail";
        }
        if (voteYatama > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para Yatama");
            return "fail";
        }
        if (voteAln > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para ALN");
            return "fail";
        }
        if (votePrn > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para APRE");
            return "fail";
        }
        if (votePli > limitVotes) {
            addErrorMessage("Cantidad de votos invalida para APLI");
            return "fail";
        }

        return "success";
    }

    public void search(ActionEvent e) {
        if (jrv != null) {
            document = getElection().getDocument(jrv, electionType, counting, round);

            jrv = getElection().getJrv(jrv.getId());
            town = jrv.getBallotCentre().getTown();
            ballots = getElection().findBallotCentres(town);
            ballotCentre = jrv.getBallotCentre();

            if (document != null) {
                this.votes = document.getVotes();

                if (this.votes != null) {
                    for (Vote vote : votes) {
                        if (vote.getParty().getInititals().equals("PLC")) {
                            votePlc = vote.getAmount();
                        } else if (vote.getParty().getInititals().equals("FSLN")) {
                            voteFsln = vote.getAmount();
                        } else if (vote.getParty().getInititals().equals("PC")) {
                            votePc = vote.getAmount();
                        } else if (vote.getParty().getInititals().equals("YATAMA")) {
                            voteYatama = vote.getAmount();
                        } else if (vote.getParty().getInititals().equals("ALN")) {
                            voteAln = vote.getAmount();
                        } else if (vote.getParty().getInititals().equals("APRE")) {
                            votePrn = vote.getAmount();
                        } else if (vote.getParty().getInititals().equals("PLI")) {
                            votePli = vote.getAmount();
                        }
                    }
                }

                fiscals = document.getFiscals();
                members = document.getMembers();
            } else {
                document = new Document();
            }
        }
    }

    public String modify() {
        System.out.println("Modification");
        if (validations().equals("fail")) {
            return "fail";
        }

        if (jrv == null) {
            addErrorMessage("Debe informar la JRV");
            return "fail";
        }
        if (jrv != null && jrv.getCode() == null) {
            addErrorMessage("Debe informar codigo de la JRV");
            return "fail";
        }

        // Modify votes for every Party
        votes = document.getVotes();

        for (Vote vote : votes) {
            if (vote.getParty().getInititals().equals("PLC")) {
                vote.setAmount(votePlc);
            }
            if (vote.getParty().getInititals().equals("FSLN")) {
                vote.setAmount(voteFsln);
            }
            if (vote.getParty().getInititals().equals("PC")) {
                vote.setAmount(votePc);
            }
            if (vote.getParty().getInititals().equals("YATAMA")) {
                vote.setAmount(voteYatama);
            }
            if (vote.getParty().getInititals().equals("ALN")) {
                vote.setAmount(voteAln);
            }
            if (vote.getParty().getInititals().equals("APRE")) {
                vote.setAmount(votePrn);
            }
            if (vote.getParty().getInititals().equals("PLI") || vote.getParty().getInititals().equals("APLI")) {
                vote.setAmount(votePli);
            }
            getElection().storeVote(vote);
        }

        document.setFiscals(fiscals);
        document.setMembers(members);

//        document.setElectionType(electionType);
//        document.setCounting(getCounting());
//        document.setRound(getRound());
        document.setJrv(jrv);
        document.setVotes(votes);

        // Audit
        Audit audit = document.getAudit();
        audit.setModifiedBy(getElection().getCurrentUser());
        audit.setModifiedDate(new Date());

        document.setAudit(audit);
        calculations();

        try {
            getElection().storeDocument(document);
        } catch (HibernateOptimisticLockingFailureException e) {
            clear(document);
            e.getMessage();
            return "fail";
        } catch (BusinessException e) {
            clear(document);
            addErrorMessage("Request was rejected, " + e.getMessage());
            return "fail";
        }

        addErrorMessage("Registro guardado");
        reset();
        return "success";
    }

    public List<Fiscal> getFiscals() {
        return fiscals;
    }

    public void setFiscals(List<Fiscal> fiscals) {
        this.fiscals = fiscals;
    }

    public String getFiscalName() {
        return fiscalName;
    }

    public void setFiscalName(String fiscalName) {
        this.fiscalName = fiscalName;
    }

    public List<Member> getMembers() {
        return members;
    }

    public void setMembers(List<Member> members) {
        this.members = members;
    }

    public String getMemberName() {
        return memberName;
    }

    public void setMemberName(String memberName) {
        this.memberName = memberName;
    }

    public List<Counting> getCountings() {
        return Arrays.asList(Counting.values());
    }

    public Integer getFiscalCount() {
        fiscalCount = fiscals.size();
        return fiscalCount;
    }

    public void setFiscalCount(Integer fiscalCount) {
        this.fiscalCount = fiscalCount;
    }

    public Integer getMemberCount() {
        memberCount = members.size();
        return memberCount;
    }

    public void setMemberCount(Integer memberCount) {
        this.memberCount = memberCount;
    }
}